using System;
using System.Text;
using System.Collections;
using System.Collections.Generic;

using SlimDX;
using SlimDX.Direct3D9;

using miciv.Rendering;

namespace miciv.Geometry.Shapes
{
    public class ShapeRectangle : ShapeBase
    {
        public static IShape Create()
        {
            return new ShapeRectangle();
        }

        public ShapeRectangle()
        {

        }

        public override bool Build(UserDataOverrideHandler _handler)
        {
            bool bResult = ((null != this.VertexDefinition)
                && (Vector3.Zero != this.Size)
                && (0 < this.LevelOfDetail));
            if (false != bResult)
            {
                BuildVertices(_handler);
                BuildTopologies(_handler);
            }
            return bResult;
        }

        private void BuildTopologies(UserDataOverrideHandler _handler)
        {
            int bandCount = this.LevelOfDetail;
            int vertexPerBand = (this.LevelOfDetail + 1) * 2;
            int bandJunctionVertexCount = 2 * (this.LevelOfDetail - 1);
            int stripSize = bandCount * vertexPerBand + bandJunctionVertexCount;
            ShapeTopology topology = new ShapeTopology(stripSize);
            topology.PrimitiveType = PrimitiveType.TriangleStrip;
            topology.PrimitiveSize = stripSize - 2;

            for (int j = 0, k = 0; this.LevelOfDetail > j; ++j)
            {
                // junction/glue between two strip bands, part two.
                if (0 != j)
                {
                    topology.Add(k);
                }
                // strip band
                for (int i = 0; this.LevelOfDetail >= i; ++i, ++k)
                {
                    topology.Add(k);
                    topology.Add(k + this.LevelOfDetail + 1);
                }
                // junction/glue between two strip bands, part one.
                if (j != (this.LevelOfDetail - 1))
                {
                    topology.Add(k + this.LevelOfDetail + 1);
                }
            }

            // basic size check.
            if (stripSize < topology.Count)
            {
                throw new Exception(string.Format("{0} : bad stripSize. {1} computed, {2} stored", this.GetType().Name, stripSize, topology.Count));
            }

            this.m_lstTopology.Add(topology);
        }

        private void BuildVertices(UserDataOverrideHandler _handler)
        {
            if (null == _handler)
            {
                this.BuildVertices();
            }
            else
            {
                int vertexCount = (this.LevelOfDetail + 1) * (this.LevelOfDetail + 1);
                this.m_arrayVertex = new ShapeVertex[vertexCount];
                for (int k = 0; vertexCount > k; ++k)
                {
                    this.m_arrayVertex[k] = new ShapeVertex();
                }

                if (false != this.VertexDefinition.HasElement("POSITION", typeof(Vector3)))
                {
                    Vector3 f3Step = new Vector3(this.Size.X / (float)this.LevelOfDetail,
                        this.Size.Y / (float)this.LevelOfDetail,
                        this.Size.Z / (float)this.LevelOfDetail);

                    for (int j = 0, k = 0; this.LevelOfDetail >= j; ++j)
                    {
                        for (int i = 0; this.LevelOfDetail >= i; ++i, ++k)
                        {
                            Vector3 f3Position = new Vector3(-this.Size.X / 2.0f + i * f3Step.X, this.Size.Y / 2.0f - j * f3Step.Y, 0.0f);
                            (this.m_arrayVertex[k] as ShapeVertex).SetElement("POSITION", f3Position, false);
                        }
                    }
                }

                if (false != this.VertexDefinition.HasElement("COLOR", typeof(Color4)))
                {
                    for (int j = 0, k = 0; this.LevelOfDetail >= j; ++j)
                    {
                        for (int i = 0; this.LevelOfDetail >= i; ++i, ++k)
                        {
                            Color4 color = (Color4)_handler("COLOR", k);
                            (this.m_arrayVertex[k] as ShapeVertex).SetElement("COLOR", color, false);
                        }
                    }
                }

                if (false != this.VertexDefinition.HasElement("UV", typeof(Vector2)))
                {
                    Vector2 f2Step = new Vector2(1.0f / (float)this.LevelOfDetail, 1.0f / (float)this.LevelOfDetail);

                    for (int j = 0, k = 0; this.LevelOfDetail >= j; ++j)
                    {
                        for (int i = 0; this.LevelOfDetail >= i; ++i, ++k)
                        {
                            Vector2 f2UV = new Vector2(i * f2Step.X, j * f2Step.Y);
                            (this.m_arrayVertex[k] as ShapeVertex).SetElement("UV", f2UV, false);
                        }
                    }
                }
            }
        }

        private void BuildVertices()
        {
            int vertexCount = (this.LevelOfDetail + 1) * (this.LevelOfDetail + 1);
            this.m_arrayVertex = new ShapeVertex[vertexCount];
            for (int k = 0; vertexCount > k; ++k)
            {
                this.m_arrayVertex[k] = new ShapeVertex();
            }

            if (false != this.VertexDefinition.HasElement("POSITION", typeof(Vector3)))
            {
                Vector3 f3Step = new Vector3(this.Size.X / (float)this.LevelOfDetail,
                    this.Size.Y / (float)this.LevelOfDetail,
                    this.Size.Z / (float)this.LevelOfDetail);

                for (int j = 0, k = 0; this.LevelOfDetail >= j; ++j)
                {
                    for (int i = 0; this.LevelOfDetail >= i; ++i, ++k)
                    {
                        Vector3 f3Position = new Vector3(-this.Size.X / 2.0f + i * f3Step.X, this.Size.Y / 2.0f - j * f3Step.Y, 0.0f);
                        (this.m_arrayVertex[k] as ShapeVertex).SetElement("POSITION", f3Position, false);
                    }
                }
            }

            if (false != this.VertexDefinition.HasElement("COLOR", typeof(Color4)))
            {
                for (int j = 0, k = 0; this.LevelOfDetail >= j; ++j)
                {
                    for (int i = 0; this.LevelOfDetail >= i; ++i, ++k)
                    {
                        (this.m_arrayVertex[k] as ShapeVertex).SetElement("COLOR", new Color4(1.0f, 1.0f, 1.0f, 1.0f), false);
                    }
                }
            }

            if (false != this.VertexDefinition.HasElement("UV", typeof(Vector2)))
            {
                Vector2 f2Step = new Vector2(1.0f / (float)this.LevelOfDetail, 1.0f / (float)this.LevelOfDetail);

                for (int j = 0, k = 0; this.LevelOfDetail >= j; ++j)
                {
                    for (int i = 0; this.LevelOfDetail >= i; ++i, ++k)
                    {
                        Vector2 f2UV = new Vector2(i * f2Step.X, j * f2Step.Y);
                        (this.m_arrayVertex[k] as ShapeVertex).SetElement("UV", f2UV, false);
                    }
                }
            }
        }
    }
}
